package com.anjubao.parking.municipal.order.service;

import com.anjubao.parking.municipal.common.dto.ApiResult;
import com.anjubao.parking.municipal.common.exception.ServiceException;
import com.anjubao.parking.municipal.common.global.BusinessCodeEnum;
import com.anjubao.parking.municipal.common.utils.BeanUtils;
import com.anjubao.parking.municipal.common.utils.MunicipalParkingUtils;
import com.anjubao.parking.municipal.common.utils.U;
import com.anjubao.parking.municipal.order.feign.ParkingTradeUserClient;
import com.anjubao.parking.municipal.order.mapper.ParkingTradeOrderMapper;
import com.anjubao.parking.municipal.order.mapper.ParkingTradeRechargeMapper;
import com.anjubao.parking.municipal.order.model.ParkingTradeOrder;
import com.anjubao.parking.municipal.order.model.ParkingTradeRecharge;
import com.anjubao.parking.municipal.payment.constant.ChargingTypeEnum;
import com.anjubao.parking.municipal.payment.constant.OrderStatusEnum;
import com.anjubao.parking.municipal.payment.constant.PayChannelIdEnum;
import com.anjubao.parking.municipal.payment.constant.TradeTypeEnum;
import com.anjubao.parking.municipal.payment.dto.*;
import com.anjubao.parking.municipal.payment.feign.ParkingTradePaymentRest;
import com.anjubao.parking.municipal.payment.form.*;
import com.anjubao.parking.municipal.user.constants.BalanceTypeEnum;
import com.anjubao.parking.municipal.user.dto.UserBalanceDto;
import com.anjubao.parking.municipal.user.dto.UserDetailDto;
import com.anjubao.parking.municipal.user.form.UserBalancePayForm;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 订单服务
 *
 * @author zhuchunfeng
 */
@Service
@Slf4j
public class ParkingTradeOrderService extends ServiceImpl<ParkingTradeOrderMapper, ParkingTradeOrder> {
    @Autowired
    private ParkingTradePaymentRest parkingTradePaymentClient;
    @Resource
    private ParkingTradeOrderMapper parkingTradeOrderMapper;
    @Autowired
    private ParkingTradeUserClient parkingTradeUserClient;
    @Resource
    private ParkingTradeRechargeMapper parkingTradeRechargeMapper;

    /**
     * 查询订单列表
     *
     * @param queryForm 订单列表查询参数
     */
    public IPage<OrderListResponseDto> queryParkingTradeOrderList(OrderListQueryForm queryForm) {

        IPage<ParkingTradeOrder> parkingTradeOrderIPage = parkingTradeOrderMapper.selectPage(
                new Page<>(
                        queryForm.getPage(),
                        queryForm.getPageSize()
                ),

                new QueryWrapper<>(new ParkingTradeOrder()
//                        .setStatus(queryForm.getStatus())  //订单状态
//                        .setGenType(queryForm.getGenType()) //生成方式
                        .setPayChannelId(queryForm.getPayChannelId()) //支付方式
                        .setStatus(OrderStatusEnum.PAID.getCode())
                ).lambda()
                        .likeRight(StringUtils.isNotBlank(queryForm.getOutTradeNo()), ParkingTradeOrder::getOutTradeNo, queryForm.getOutTradeNo()) //订单编号
                        .likeRight(StringUtils.isNotBlank(queryForm.getParkingLotName()), ParkingTradeOrder::getParkingLotName, queryForm.getParkingLotName()) //停车场名称
                        .likeRight(StringUtils.isNotBlank(queryForm.getPlateNumber()), ParkingTradeOrder::getPlateNumber, queryForm.getPlateNumber()) //车牌号
                        .gt(queryForm.getOrderTimeStart() != null, ParkingTradeOrder::getCreateTime, queryForm.getOrderTimeStart()) //创建时间
                        .lt(queryForm.getOrderTimeEnd() != null, ParkingTradeOrder::getCreateTime, queryForm.getOrderTimeEnd()) //创建时间
                        .orderByDesc(ParkingTradeOrder::getCreateTime)
        );
        return parkingTradeOrderIPage.convert(t -> BeanUtils.transform(OrderListResponseDto.class, t));
    }

    public OrderResponseDto submitOrder(SubmitOrderForm submitOrderForm) {

        /*数据校验*/
        String businessId = submitOrderForm.getBusinessId();
        List<ParkingTradeOrder> parkingTradeOrders = parkingTradeOrderMapper.selectList(new QueryWrapper<>(new ParkingTradeOrder().setBusinessId(businessId)));
        if (!CollectionUtils.isEmpty(parkingTradeOrders)) {
            throw new ServiceException("businessId为" + businessId + "的订单已经存在, 请更换快捷支付接口获取支付参数");
        }

        /*生成订单 - 并插入数据库*/
        ParkingTradeOrder order = new ParkingTradeOrder();
        //生成ID和code
        order.setOutTradeId(U.id());
        order.setOutTradeNo(MunicipalParkingUtils.generateCode(order.getOutTradeId(), BusinessCodeEnum.PARKING_ORDER_CODE.getCode()));
        order.setRemoteParkingRecordId(submitOrderForm.getRemoteParkingRecordId());
        order.setTotalFee(submitOrderForm.getTotalFee());
        order.setPayFee(submitOrderForm.getTotalFee());
        order.setPayerCustomerId(submitOrderForm.getUserCode());
        order.setDescription("");
        order.setPlateNumber(submitOrderForm.getVehicle());
        order.setParkingLotSlotCode("");
        order.setParkingLotSlotName(submitOrderForm.getParkingLotSlotName());
        order.setParkingLotName(submitOrderForm.getParkingLotName());
        order.setTimeStart(LocalDateTime.now());
        order.setBusinessId(submitOrderForm.getBusinessId());
        order.setStatus(OrderStatusEnum.UN_PAID.getCode());
        order.setStatusDesc(OrderStatusEnum.UN_PAID.getDesc());
        order.setType(submitOrderForm.getOrderType());
        order.setGenType(1);
        order.setChargingType(ChargingTypeEnum.COMMON.getCode());
        order.setIsReserve(0);
        order.setPayerCustomerId(submitOrderForm.getUserCode());
        order.setPayerPhone("");
        order.setParkingRecordId(1L);
        parkingTradeOrderMapper.insert(order);

        /*获取订单支付参数*/
        return payOrder(order, submitOrderForm.getPayChannelId());

    }

    /**
     * 支付订单
     */
    public OrderResponseDto quickPay(PayOrderForm payOrderForm) {
        ParkingTradeOrder order = parkingTradeOrderMapper.selectOne(new QueryWrapper<>(new ParkingTradeOrder()
                .setOutTradeNo(payOrderForm.getOutTradeNo())
                .setBusinessId(payOrderForm.getBusinessId())
        ));
        if (null == order) {
            throw new ServiceException("订单记录不存在");
        }
        if (!OrderStatusEnum.UN_PAID.getCode().equals(order.getStatus())) {
            throw new ServiceException("订单不是未支付状态");
        }

        return payOrder(order, payOrderForm.getPayChannelId());

    }

    /**
     * payChannelId : 1：微信支付 2:支付宝支付 3:银联支付 4:余额支付 5:余额支付 99:其他
     */
    private OrderResponseDto payOrder(ParkingTradeOrder order, Integer payChannelId) {
        log.info("收到支付订单请求 order:{} payChannelId:{} ",U.json(order),payChannelId);

        //微信支付
        if (PayChannelIdEnum.WX_PAY.getCode().equals(payChannelId)) {

            //获取用户openId
            ApiResult<UserDetailDto> userInfo = parkingTradeUserClient.getUserInfo(order.getPayerCustomerId());
            log.info("会员信息 userInfo: {}",U.json(userInfo));
            if (null == userInfo.getResult()) {
                throw new ServiceException("会员不存在?");
            }

            /*去支付中心获取微信支付参数*/
            WxPayJsapiForm payRequestForm = new WxPayJsapiForm();
            payRequestForm.setOutTradeNo(order.getOutTradeNo());
            payRequestForm.setOpenid(userInfo.getResult().getMinappOpenid());
            payRequestForm.setTotalFee(order.getTotalFee());

            log.info("请求微信支付 payRequestForm: {}", payRequestForm);
            ApiResult<PayResponseDto> payResponseDtoApiResult = parkingTradePaymentClient.wxPayJsapi(payRequestForm);
            if (payResponseDtoApiResult.getCode() == 5000) {
                throw new ServiceException(payResponseDtoApiResult.getDesc());
            }

            /*数据组装并返回*/
            return new OrderResponseDto()
                    .setOrder(new OrderInfoDto()
                            .setOutTradeNo(order.getOutTradeNo()))
                    .setPayment(payResponseDtoApiResult.getResult());

        }

        //余额支付
        if (PayChannelIdEnum.CASH.getCode().equals(payChannelId)) {

            /*去用户中心扣减用户余额*/
            UserBalancePayForm userBalancePayForm = new UserBalancePayForm();
            userBalancePayForm.setAmount(order.getTotalFee());
            userBalancePayForm.setType(BalanceTypeEnum.CONSUME.getCode()); //2消费
            userBalancePayForm.setUserCode(order.getPayerCustomerId());
            userBalancePayForm.setTradeOrderId(order.getOutTradeId().toString());
            userBalancePayForm.setRecodeId(order.getBusinessId());

            /*是否支付成功*/
            ApiResult<UserBalanceDto> userBalanceDtoApiResult = parkingTradeUserClient.balancePay(userBalancePayForm);
            if (userBalanceDtoApiResult.getCode() == 5000) {
                throw new ServiceException(userBalanceDtoApiResult.getDesc());
            }

            /*支付成功 更新订单状态 未支付->已支付 根据update判断更新结果*/
            UserBalanceDto userBalanceDto = userBalanceDtoApiResult.getResult();
            ParkingTradeOrder parkingTradeOrder =new ParkingTradeOrder()
                    //支付完成时间，格式为yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
                    .setFulfillTime(userBalanceDto.getCreateTime()) //支付时间
                    .setStatus(OrderStatusEnum.PAID.getCode()) //已支付
                    .setStatusDesc(OrderStatusEnum.PAID.getDesc())
                    .setPayChannelId(PayChannelIdEnum.CASH.getCode()) //余额支付
                    .setTransactionId(userBalanceDto.getId().toString()); //微信支付id;
            UpdateWrapper<ParkingTradeOrder> updateWrapper = new UpdateWrapper<>();
            updateWrapper.setEntity(new ParkingTradeOrder()
                    .setStatus(OrderStatusEnum.UN_PAID.getCode()) //未支付
                    .setOutTradeId(order.getOutTradeId())); //id
            int update = parkingTradeOrderMapper.update(parkingTradeOrder, updateWrapper);
            if (update != 1) {
                //todo 重复支付,掉单校验
                log.error("支付异常");
            }

            /*组装数据并返回*/
            return new OrderResponseDto()
                    .setOrder(new OrderInfoDto()
                            .setOutTradeNo(order.getOutTradeNo()))
                    .setBalancePayDto(new BalancePayDto()
                            .setPayTime(LocalDateTime.now())
                            .setResultCode(1));
//            payResponseDtoApiResult = parkingTradePaymentClient.wxPayNative(payRequestForm);
        }
        throw new ServiceException("暂不支持的支付方式");
    }


    /**
     * 余额充值
     * @param balanceRechargeForm 余额充值请求参数
     * @return 余额充值
     */
    public PayResponseDto balanceRecharge(BalanceRechargeForm balanceRechargeForm) {

        //校验用户是否存在信息
        String userCode = balanceRechargeForm.getUserCode();
        ApiResult<UserDetailDto> userInfo = parkingTradeUserClient.getUserInfo(userCode);
        if (userInfo.getResult() == null) {
            throw new ServiceException("用户不存在");
        }

        //入库充值记录
        ParkingTradeRecharge parkingTradeRecharge = new ParkingTradeRecharge();
        parkingTradeRecharge.setOutTradeId(U.id());
        parkingTradeRecharge.setOutTradeNo(MunicipalParkingUtils.generateCode(parkingTradeRecharge.getOutTradeId(),BusinessCodeEnum.PARKING_ORDER_CODE.getCode()));
        parkingTradeRecharge.setTotalFee(balanceRechargeForm.getTotalFee());
        parkingTradeRecharge.setOrderTime(LocalDateTime.now());
        parkingTradeRecharge.setPayType(TradeTypeEnum.JSAPI.getCode());
        parkingTradeRecharge.setPayerOpenid(userInfo.getResult().getMinappOpenid());
        parkingTradeRecharge.setPayerPhone("");
        parkingTradeRecharge.setPayerCustomerId(balanceRechargeForm.getUserCode());
        parkingTradeRecharge.setPayChannelId(PayChannelIdEnum.WX_PAY.getCode());
        parkingTradeRecharge.setTransactionId("");
        parkingTradeRecharge.setBusinessId(balanceRechargeForm.getBusinessId());
        parkingTradeRecharge.setStatus(OrderStatusEnum.UN_PAID.getCode());
        parkingTradeRecharge.setStatusDesc(OrderStatusEnum.UN_PAID.getDesc());
        parkingTradeRecharge.setFulfillTime(null);
        parkingTradeRechargeMapper.insert(parkingTradeRecharge);



        //请求微信支付接口拉起支付
        WxPayJsapiForm payRequestForm = new WxPayJsapiForm();
        payRequestForm.setOpenid(userInfo.getResult().getMinappOpenid());
        payRequestForm.setAttach(userCode);
        payRequestForm.setOutTradeNo(parkingTradeRecharge.getOutTradeNo());
        payRequestForm.setTotalFee(balanceRechargeForm.getTotalFee());
        ApiResult<PayResponseDto> payResponseDtoApiResult = parkingTradePaymentClient.wxPayJsapi(payRequestForm);
        if (payResponseDtoApiResult.getCode() == 5000) {
            throw new ServiceException(payResponseDtoApiResult.getDesc());
        }
        return payResponseDtoApiResult.getResult();
    }

    /**
     * 查询订单详情
     *
     * @return 订单详情
     */
    public ParkingTradeOrder queryOrderDetail(String businessId, Integer orderType) {

        QueryWrapper<ParkingTradeOrder> queryWrapper = new QueryWrapper<>(
                new ParkingTradeOrder()
                        .setBusinessId(businessId)
                        .setType(orderType)
        );
        ParkingTradeOrder order = parkingTradeOrderMapper.selectOne(queryWrapper);
        if (null == order) {
            throw new ServiceException("无此订单");
        }
        return order;
    }


    /**
     * 查询订单支付
     *
     * @param businessId 子系统业务id
     * @param orderType  订单类型 1-停车订单 2-支付订单
     * @return 订单状态
     */
    public PayNotifyDto queryOrderStatus(String businessId, Integer orderType) {
        ParkingTradeOrder order = this.queryOrderDetail(businessId, orderType);
        PayNotifyDto payNotifyDto = new PayNotifyDto();
        payNotifyDto.setBusinessId(order.getBusinessId());
        payNotifyDto.setPayTime(order.getFulfillTime());
        payNotifyDto.setOrderType(order.getType());
        payNotifyDto.setOpenid(order.getPayerOpenid());
        payNotifyDto.setStatus(order.getStatus());
        return payNotifyDto;

    }

}
